/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package JET.mygui;

import JET.mygui.CenterTabsPane.CenterTabsPaneTab;
import JET.mygui.UtilTabsPane.UtilTabsPaneTab;
import JET.mygui.interfaces.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import org.w3c.dom.*;

/**
 *
 * @author 057Ry
 */
public class MultiSplitPaneCell extends JPanel implements MouseListener, MyGuiDnDReady {

    public static int idCounter=0;
    private int id = idCounter++;
    private boolean resizable = true;

    public MultiSplitPaneCell(boolean r) {
        setLayout(new BorderLayout());
        setBackground(Color.WHITE);
        addMouseListener(this);
        MyGuiManager.getInstance().registerDnDReady(this);

        this.resizable = r;
    }

    public boolean isResizable() {
        return resizable;
    }

    public MultiSplitPane getMultiSplitPane() {
        return (MultiSplitPane) this.getParent();
    }

    public boolean containsComponent(Component comp) {
        for(Component c : getComponents())
            if (c.equals(comp))
                return true;
        return false;
    }

    ////////////////////////////////////////////////////////////////////////////
    //                            P A I N T I N G                             //
    ////////////////////////////////////////////////////////////////////////////
    
    @Override
    public void paintComponent(Graphics g) {
        
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, getWidth()-1, getHeight()-1);
        g.setColor(Color.RED);
        g.drawLine(0, 0, getWidth(), getHeight());
        g.setColor(Color.GREEN);
        g.drawLine(getWidth(), 0, 0, getHeight());
        g.setColor(Color.BLACK);
        g.drawString(""+this, 10, 10);
    }

    
    ////////////////////////////////////////////////////////////////////////
    //               M O U S E   L I S T E N E R S   S T U F F            //
    ////////////////////////////////////////////////////////////////////////

    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}

    public String toString(int level) {
        String str = "";

        for(int i=0; i<getComponentCount(); i++) {
            if (getComponent(i) instanceof TabsPane) {
                TabsPane c = (TabsPane) MyGuiHelper.getComponentAfterScrollPane((JComponent) getComponent(i));
                str += MyGuiHelper.appendSpaces((level+1)*4, c.toString(level+1) + ",\n");
            }
            else if (getComponent(i) instanceof MultiSplitPane) {
                MultiSplitPane c = (MultiSplitPane) MyGuiHelper.getComponentAfterScrollPane((JComponent) getComponent(i));
                str += MyGuiHelper.appendSpaces((level+1)*4, c.toString(level+1) + ",\n");
            }
        }
        String ret = "Cell[id: "+id+"]{\n"+str+ MyGuiHelper.appendSpaces((level)*4,"}");
        MyGuiHelper.appendSpaces(level*4, ret);
        return ret;
    }

    
    ////////////////////////////////////////////////////////////////////////
    //               D R A G   A N D   D R O P   U T I L S                //
    ////////////////////////////////////////////////////////////////////////

    /**
     * Calculates rectagles that take active part in MyGuiDrag and Drop
     * mechanism. Other ares than those are transparent for my gui manager
     * which makes MultiSplitPaneCell parent and ancestors e visible to the MyGuiManager.
     *
     * @return Array of rectangles which are active drag and drop TabsPane areas.
     *         Rectangles coordinates are specified in MultiSplitPaneCell local system.
     */
    private Rectangle[] getActiveDnDAreas() {
        Rectangle[] rects = new Rectangle[5];

        double  spaceH = .75, // Percentage center space width
                spaceV = .75; // Precentage center space height

        // Center area dimensions
        int x = (int)(getWidth()  * (1-spaceH)/2),
            y = (int)(getHeight() * (1-spaceV)/2),
            w = (int)(getWidth()  * spaceH),
            h = (int)(getHeight() * spaceV);

        // Center rectangle
        rects[0] = new Rectangle(x, y, w, h);
        // Top
        rects[1] = new Rectangle(0,0, getWidth(), y);
        // Right
        rects[2] = new Rectangle(x+w, y, x, h);
        // Bottom
        rects[3] = new Rectangle(0, y+h, getWidth(), y);
        // Left
        rects[4] = new Rectangle(0, y, x, h);

        return rects;
    }

    private void insertNewCellAt(Component compToDrop, int toIndex) {
        TabsPane tp = MyGuiHelper.getNewTabsPaneForTab(compToDrop);
        
        // Note that this call to add method may remove object from its last parent
        tp.add(compToDrop);

        getMultiSplitPane().insert(tp, false, toIndex, 100);
        getMultiSplitPane().repairSizes();
    }

    /**
     * Encolse cell of horizontal mulsti split pane in new created vertical split pane.
     *
     * @param compToDrop
     * @param lastParent
     * @param sp
     * @param toIndex
     */
    private void encloseHorizCellInVMSP(Component compToDrop, int toIndex) {
        

        JComponent cellComp = null;
//        System.out.println("MSPCell, getComponentCount() = "+getComponentCount());
        if (getComponentCount()>0) {
            cellComp = (JComponent)getComponent(0);
            remove(cellComp);
//            System.out.println("MSPCell, cellComp removed, getComponentCount() = "+getComponentCount());
//            System.out.println("MSPCell, cellComp: "+cellComp);
        }

        MultiSplitPane newSp = new MultiSplitPane(1, false);
        add(newSp);
        newSp.setCellComponent(0, cellComp, true);

        TabsPane newTp = MyGuiHelper.getNewTabsPaneForTab(compToDrop);
        newTp.add(compToDrop);
        newSp.insert(newTp, false, toIndex, 100);
        newSp.getCell(toIndex).setSize(toIndex, 100);
    }

    /**
     * Encolse cell of vertical mulstisplit pane in new created horizontal split pane.
     */
    private void encloseVertCellInHMSP(Component compToDrop, int toIndex) {

        JComponent cellComp = null;
        if (getComponentCount()>0) {
            cellComp = (JComponent)getComponent(0);
            remove(cellComp);
        }

        MultiSplitPane newSp = new MultiSplitPane(1, true);
        add(newSp);
        newSp.setCellComponent(0, cellComp, true);

        TabsPane newTp = MyGuiHelper.getNewTabsPaneForTab(compToDrop);
        newTp.add(compToDrop);
        newSp.insert(newTp, false, toIndex, 100);
        newSp.getCell(toIndex).setSize(toIndex, 100);
    }

    
    ////////////////////////////////////////////////////////////////////////////
    //                      D R A G   A N D   D R O P                         //
    ////////////////////////////////////////////////////////////////////////////

    public void registerGuiManager(MyGuiManager manager) {
        addMouseMotionListener(manager);
        addMouseListener(manager);
    }

    public void dndRemove(Object o) {
        remove((Component)o);
    }

    public Point getDnDLocationOnScreen() {
        return getLocationOnScreen();
    }

    public Rectangle getDnDBounds() {
        return getBounds();
    }

    public JComponent getObjectToPickAt(Point p) {
        //return (JComponent) getComponentAt(p);
        return null;
    }

    public boolean isValidDropLocation(Point p) {
        Rectangle[] rects = getActiveDnDAreas();
        
        for(int i=1; i<rects.length; i++)
            if (rects[i].contains(p))
                return true;
        
        return false;
    }

    public boolean accepts(Object o) {
        if (o==null) return false;
        if (o instanceof JComponent)
            return true;

        return false;
    }

    public boolean dropObjectAt(Object o, Point p) {
        try {
            if (o==null)
                return false;

            Component compToDrop = (Component) o;
            MultiSplitPane sp = getMultiSplitPane();
            if (sp==null) return false;

            Rectangle[] rects = getActiveDnDAreas();
            // TOP
            if (rects[1].contains(p)) {
                if (sp.isHorizontal()) {
                    encloseHorizCellInVMSP(compToDrop, 0);
                    return true;
                } else {
                    int toIndex = sp.getCellIndex(this);
                    insertNewCellAt(compToDrop, toIndex);
                    return true;
                }
            } 
            // RIGHT
            else if (rects[2].contains(p)) {
                if (sp.isHorizontal()) {
                    int toIndex = sp.getCellIndex(this)+1;
                    insertNewCellAt(compToDrop, toIndex);
                    return true;
                } else {
                    // heeeejr
                    encloseVertCellInHMSP(compToDrop, 1);
                    return true;
                }
            }
            // Bottom
            else if (rects[3].contains(p)) {
                if (sp.isHorizontal()) {
                    encloseHorizCellInVMSP(compToDrop, 1);
                    return true;
                } else {
                    // Store dropped object parent reference
                    int toIndex = sp.getCellIndex(this)+1;
                    insertNewCellAt(compToDrop, toIndex);
                    return true;
                }
            }
            // Left
            else if (rects[4].contains(p)) {
                if (sp.isHorizontal()) {
                    // Store dropped object parent reference
                    int toIndex = sp.getCellIndex(this);
                    insertNewCellAt(compToDrop, toIndex);
                    return true;
                } else {
                    // end heeeejr
                    encloseVertCellInHMSP(compToDrop, 0);
                    return true;
                }
            }

            return false;
            
        } catch(Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //                        X M L   S T U F F                               //
    ////////////////////////////////////////////////////////////////////////////

    public Element getXMLElement(Document doc) throws Exception {
        Element root = doc.createElement("cell");

        int index = getMultiSplitPane().getCellIndex(this);
        int size = getMultiSplitPane().getCellSize(index);
        
        root.setAttribute("size", ""+size);

        Object cellComp = MyGuiHelper.getComponentAfterScrollPane( (JComponent)getComponent(0) );
        if (cellComp instanceof MultiSplitPane) {
            root.appendChild( ((MultiSplitPane)cellComp).getXMLElement(doc) );
        }
        else if (cellComp instanceof TabsPane) {
            root.appendChild( ((TabsPane)cellComp).getXMLElement(doc) );
        }
        else
            throw new Exception("Undefined object in MSP Cell!");
        
//        else if (cellComp instanceof CenterTabsPaneTab) {
//            CenterTabsPaneTab tab = (CenterTabsPaneTab)cellComp;
//            Element el = doc.createElement("tab");
//            el.setAttribute("type", "center");
//            el.setAttribute("id", ""+tab.getTabType());
//            root.appendChild(el);
//        }
//        else if (cellComp instanceof UtilTabsPaneTab) {
//            UtilTabsPaneTab tab = (UtilTabsPaneTab)cellComp;
//            Element el = doc.createElement("tab");
//            el.setAttribute("type", "util");
//            el.setAttribute("id", ""+tab.getId());
//            root.appendChild(el);
//        }

        return root;
    }

    /**
     * Creates object that will be drawn on glass pane and show future
     * layout position of object that will be dropped at location p.
     *
     * @param p Point at which objects is to be dropped (specified in cell local system).
     * @return New object drawing future layout and position on a glass pane.
     */
    public MyGuiDnDDrawable getFutureLayoutDrawable(Point p) {
        Rectangle[] rects = getActiveDnDAreas();
        for(int i=1; i<rects.length; i++)
            if (rects[i].contains(p))
                if (i==1 || i==3)
                    return new FutureLayoutDrawable(rects[i]);
                else
                    return new FutureLayoutDrawable( new Rectangle((int)rects[i].getX(), 0,
                                                            (int)rects[i].getWidth(),
                                                            (int)getHeight()) );

        return new FutureLayoutDrawable(getActiveDnDAreas()[0]);
    }

    ////////////////////////////////////////////////////////////////////////////
    //          F U T U R E   L A Y O U T   D R A W A B L E                   //
    ////////////////////////////////////////////////////////////////////////////

    /**
     * Represents an object that is passed to glass pane of gui manager to draw
     * future layout and position of object that would be dropped onto this cell.
     */
    private class FutureLayoutDrawable implements MyGuiDnDDrawable {

        /** Rectangle in screen coordinates system */
        public Rectangle rect;

        public FutureLayoutDrawable(Rectangle rect) {
            this.rect = new Rectangle((int)(rect.getX()+MultiSplitPaneCell.this.getLocationOnScreen().getX()),
                                      (int)(rect.getY()+MultiSplitPaneCell.this.getLocationOnScreen().getY()),
                                      (int)(rect.getSize().getWidth()),
                                      (int)(rect.getSize().getHeight()) );
        }

        public void paintDrawabe(Graphics g, Component comp) {
            Graphics2D g2d = (Graphics2D) g;
            Point lP = rect.getLocation();
            SwingUtilities.convertPointFromScreen(lP, comp);
            g2d.setColor(Color.ORANGE);

            g2d.draw(new Rectangle(lP, rect.getSize()));
            g2d.draw(new Rectangle(lP.x+1, lP.y+1, (int)rect.getSize().getWidth()-2, (int)rect.getSize().getHeight()-2));
        }
    }
    
}
